<?php

namespace App\Http\Controllers\Search;

use App\Http\Controllers\ApiController;
use App\Models\CnDiagnose;
use App\Models\MedicalRecord;
use App\Project\Search\Factory;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;

/**
 * 病历搜索控制器
 * @package App\Http\Controllers\Search
 */
class SearchController extends ApiController
{
    /**
     * @var Request
     */
    protected $request;

    /**
     * @var \App\Project\Search\Factory
     */
    protected $factory;

    /**
     * @var array
     */
    protected $condition;

    protected $types;

    /**
     * SearchController constructor.
     * @param $request
     */
    public function __construct(Request $request)
    {
        parent::__construct();

        $this->request   = $request;
        $this->condition = $this->request->input();
        $this->factory   = new Factory($this->condition);
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     * @throws \App\Project\Search\Exception\MedicalRecordSearchException
     */
    public function index()
    {
        /** @var \Illuminate\Pagination\LengthAwarePaginator $paginate */
        $paginate = $this->getBuilder(false, [
            'st_medical_records.id',
            'st_medical_records.patient_id',
            'tn_user_base.name',
            'tn_user_base.sex',
            'tn_user_base.age',
            'tn_user_base.phone',
            'tn_user_base.medical_number',
        ])->groupBy('patient_id')
                         ->orderBy('st_medical_records.id', 'desc')
                         ->paginate()->appends($this->condition);

        if ($paginate->count()) {
            /** @var \Illuminate\Database\Eloquent\Collection $result */
            $result = $paginate->getCollection();

            $this->factory->reset();

            $col = $this->getBuilder(true,
                ['tn_user_base.id as patient_id', 'st_medical_records.id', 'st_medical_records.clinic_at'])
                        ->whereIn('tn_user_base.id', $result->pluck('patient_id')->toArray())
                        ->get()->unique('id');

            $col = $this->factory->translate($this->cnDiagnose($col))->sortByDesc('record_id')->groupBy('patient_id');

            $result->map(function (MedicalRecord $record) use ($col) {
                $record->setAttribute('records', $col->get($record->patient_id)->toArray());
            });

            $paginate->setCollection($result);
        }

        return $this->paginate($paginate, $this->transformer());
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     * @throws \App\Project\Search\Exception\MedicalRecordSearchException
     */
    public function export()
    {
        $result = $this->getBuilder(true, array_merge($this->searchField(), ['st_medical_records.clinic_at']))
                       ->groupBy('st_medical_records.id')->get();

        return $this->collection($this->factory->translate($this->cnDiagnose($result)), $this->transformer());
    }

    /**
     * @param bool  $extract 是否 select装饰表的字段
     * @param array $field   要查询的字段
     * @return \Illuminate\Database\Eloquent\Builder
     * @throws \App\Project\Search\Exception\MedicalRecordSearchException
     */
    protected function getBuilder($extract = false, $field = [])
    {
        /** @var \Illuminate\Database\Eloquent\Builder $builder */
        $builder = MedicalRecord::where($this->sceneWhere())
                                ->join('tn_user_base', 'tn_user_base.id', 'st_medical_records.patient_id')
                                ->select($field);
        $this->factory->setExtract($extract);

        return $this->factory->setDb($builder)->getBuilder();
    }

    /**
     * @return array
     */
    protected function sceneWhere()
    {
        $user  = \Auth::user();
        $where = [];
        if (!$user->isAdmin() && !$user->isDoctorsAdmin()) {
            $where[] = ['st_medical_records.hospital_id', '=', $user->hospital_id];
            $where[] = ['st_medical_records.doctor_id', '=', $user->id];
        } elseif ($user->isDoctorsAdmin()) {
            $where[] = ['st_medical_records.hospital_id', '=', $user->hospital_id];
        }

        return $where;
    }

    /**
     * @return \Closure
     */
    protected function transformer()
    {
        return function ($result) {
            $result['sex'] = ['男', '女'][$result['sex']];

            return collect($result)->map(function ($item) {
                return is_string($item) ? trim($item, '"') : $item;
            })->toArray();
        };
    }

    protected function searchField()
    {
        return [
            'st_medical_records.id',
            'st_medical_records.patient_id',
            'tn_user_base.name',
            'tn_user_base.sex',
            'tn_user_base.age',
            'tn_user_base.phone',
            'tn_user_base.medical_number',
        ];
    }

    protected function cnDiagnose(Collection $results)
    {
        if ($this->request->has('cn_diagnose-d') && $results->count()) {

            $this->types = app('field')->get('diagnose.cn_diagnose');
            return $results->map(function (MedicalRecord $record) {
                $record->cnDiagnose->map(function (CnDiagnose $diagnose) {
                    $diagnose->type = $this->types['type'][$diagnose->type_id];

                    return $diagnose;
                });

                return $record;
            });
        }

        return $results;
    }
}
